﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using SlimDX;
using Editor.Rendering;

namespace Editor
{
    public class GridMesh
    {
        public enum Axis
        {
            XY,
            XZ,
            YZ
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct VertexPositionColor
        {
            public Vector3 position;
            public int color;

            public VertexPositionColor(Vector3 _position, int _color)
            {
                position = _position;
                color = _color;
            }
        };

        private const int k_NumLineVerts = 170;
        private SlimDX.Direct3D9.VertexBuffer m_LineVertexBuffer;
        private Material m_Material;
        private Shader m_Shader;

        private int m_GridSpacing = 0;
        private Axis m_GridAxis = Axis.XY;

        public int GridSpacing
        {
            get { return m_GridSpacing; }
            set { m_GridSpacing = value; }
        }

        public Axis GridAxis
        {
            get { return m_GridAxis; }
            set { m_GridAxis = value; }
        }

        public GridMesh()
        {
        }

        #region Create Grid
        public void Create(SlimDX.Direct3D9.Device device)
        {
            System.Diagnostics.Debug.Assert(m_GridSpacing > 0);

            if (m_Shader == null)
            {
                m_Shader = new Shader(device, @"c:\temp\data\PositionColor.fx");
            }

            if (m_Material == null)
            {
                m_Material = new Material(device, m_Shader);
            }

            if (m_LineVertexBuffer != null)
            {
                m_LineVertexBuffer.Dispose();
            }

            float gridSpacing = (float)m_GridSpacing;
            float halfGridSize = 20.0f * gridSpacing;

            m_LineVertexBuffer = new SlimDX.Direct3D9.VertexBuffer(device,
                                                  k_NumLineVerts * Marshal.SizeOf(typeof(VertexPositionColor)),
                                                  SlimDX.Direct3D9.Usage.WriteOnly,
                                                  SlimDX.Direct3D9.VertexFormat.None,
                                                  SlimDX.Direct3D9.Pool.Managed);

            DataStream lineStream = m_LineVertexBuffer.Lock(0, 0, SlimDX.Direct3D9.LockFlags.None);

            Color col = Color.FromArgb(128, 128, 128);
            if (m_GridAxis == Axis.XY)
                CreateGridVerticesXY(gridSpacing, halfGridSize, col, lineStream);
            else if (m_GridAxis == Axis.XZ)
                CreateGridVerticesXZ(gridSpacing, halfGridSize, col, lineStream);
            else if (m_GridAxis == Axis.YZ)
                CreateGridVerticesYZ(gridSpacing, halfGridSize, col, lineStream);

            lineStream.Write(new VertexPositionColor(new Vector3(0, 0, 0), Color.Red.ToArgb()));
            lineStream.Write(new VertexPositionColor(new Vector3(halfGridSize, 0, 0), Color.Red.ToArgb()));
            lineStream.Write(new VertexPositionColor(new Vector3(0, 0, 0), Color.Green.ToArgb()));
            lineStream.Write(new VertexPositionColor(new Vector3(0, halfGridSize, 0), Color.Green.ToArgb()));
            lineStream.Write(new VertexPositionColor(new Vector3(0, 0, 0), Color.Blue.ToArgb()));
            lineStream.Write(new VertexPositionColor(new Vector3(0, 0, halfGridSize), Color.Blue.ToArgb()));
            m_LineVertexBuffer.Unlock();
        }

        private void CreateGridVerticesXY(float gridSpacing, float halfGridSize, Color col, DataStream lineStream)
        {
            for (int i = -20; i <= 20; i++)
            {
                float halfGridEnd = (i != 0) ? halfGridSize : 0.0f;

                {
                    Vector3 position = new Vector3((float)i * gridSpacing, -halfGridSize, 0.0f);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
                {
                    Vector3 position = new Vector3((float)i * gridSpacing, halfGridEnd, 0.0f);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
                {
                    Vector3 position = new Vector3(-halfGridSize, (float)i * gridSpacing, 0.0f);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
                {
                    Vector3 position = new Vector3(halfGridEnd, (float)i * gridSpacing, 0.0f);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
            }
        }

        private void CreateGridVerticesXZ(float gridSpacing, float halfGridSize, Color col, DataStream lineStream)
        {
            for (int i = -20; i <= 20; i++)
            {
                float halfGridEnd = (i != 0) ? halfGridSize : 0.0f;

                {
                    Vector3 position = new Vector3((float)i * gridSpacing, 0.0f, -halfGridSize);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
                {
                    Vector3 position = new Vector3((float)i * gridSpacing, 0.0f, halfGridEnd);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
                {
                    Vector3 position = new Vector3(-halfGridSize, 0.0f, (float)i * gridSpacing);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
                {
                    Vector3 position = new Vector3(halfGridEnd, 0.0f, (float)i * gridSpacing);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
            }
        }

        private void CreateGridVerticesYZ(float gridSpacing, float halfGridSize, Color col, DataStream lineStream)
        {
            for (int i = -20; i <= 20; i++)
            {
                float halfGridEnd = (i != 0) ? halfGridSize : 0.0f;

                {
                    Vector3 position = new Vector3(0.0f, (float)i * gridSpacing, -halfGridSize);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
                {
                    Vector3 position = new Vector3(0.0f, (float)i * gridSpacing, halfGridEnd);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
                {
                    Vector3 position = new Vector3(0.0f, -halfGridSize, (float)i * gridSpacing);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
                {
                    Vector3 position = new Vector3(0.0f, halfGridEnd, (float)i * gridSpacing);
                    VertexPositionColor cv = new VertexPositionColor(position, col.ToArgb());
                    lineStream.Write(cv);
                }
            }
        }
        #endregion

        public void Render(SlimDX.Direct3D9.Device device, Matrix matView, Matrix matProjection)
        {
            m_Material.Render(device, Matrix.Identity, matView, matProjection, m_LineVertexBuffer, typeof(VertexPositionColor), k_NumLineVerts, null, SlimDX.Direct3D9.PrimitiveType.LineList, k_NumLineVerts / 2);
        }
    }
}
